﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using fastJSON;
using Less.Core;

namespace Less.Util
{
    public static class Functions
    {
        /// <summary>
        /// Go thru the stack to get the calling method name.
        /// </summary>
        /// <returns></returns>
        public static string GetCallingMethodName(int steps = 2)
        {
            string callingMethod = String.Empty;
            var stack = new StackTrace(steps);
            StackFrame frame = stack.GetFrame(0);
            if (frame != null)
            {
                MethodBase method = frame.GetMethod();
                if (method != null)
                {
                    callingMethod = GetFriendlyName(method);
                    callingMethod = ShortString(callingMethod);
                }
            }
            return callingMethod;
        }

        /// <summary>
        /// Go thru the stack to get the calling method name.
        /// </summary>
        /// <returns></returns>
        public static MethodBase GetCallingMethod(int steps = 2)
        {
            MethodBase callingMethod = null;
            var stack = new StackTrace(steps);
            StackFrame frame = stack.GetFrame(0);
            if (frame != null)
                callingMethod = frame.GetMethod();
            return callingMethod;
        }

        public static string GetFriendlyName(MethodBase method)
        {
            if (method == null) throw new ArgumentNullException("method");
            return method.DeclaringType + "." + method.Name;
        }

        /// <summary>
        /// Format to get less verbose logs
        /// </summary>
        /// <param name="me"></param>
        /// <returns></returns>
        public static string ShortString(string me)
        {
            if (me.HasValue())
            {
                string shortName = me.Trim();
                shortName = shortName.Replace("System.", "S.");
                shortName = shortName.Replace("Data.", "D.");
                shortName = shortName.Replace("SqlServer", "Sql");
                shortName = shortName.Replace("Connection", "Cnn");
                shortName = shortName.Replace("Command", "Cmd");
                shortName = shortName.Replace("Database", "Db");
                shortName = shortName.Replace("Exception", "Excp");
                shortName = shortName.Replace("Execute", "Exct");
                shortName = shortName.Replace("Framework", "Frmw");
                shortName = shortName.Replace("Less", "Ls");
                return shortName;
            }
            return String.Empty;
        }

        public static string CleanMessage(string msg)
        {
            return
                msg.Replace("'", "").Replace("\"", "").Replace(Environment.NewLine, " -- ").Replace("\r", " -- ").
                    Replace("\n", " -- ");
        }

        public static string ReadText(string filePath)
        {
            if (filePath == null) throw new ArgumentNullException("filePath");
            string textReaded = String.Empty;
            if (File.Exists(filePath))
            {
                using (var stream = new StreamReader(filePath))
                {
                    textReaded += stream.ReadToEnd();
                    stream.Close();
                }
            }
            else
                Log.Warning(Msg.PathNotFound(filePath));
            return textReaded;
        }

        public static void WriteText(string filePath, string text)
        {
            if (filePath == null) throw new ArgumentNullException("filePath");
            string directory = Path.GetDirectoryName(filePath);
            VerifyDirectory(directory);
            using (var file = new StreamWriter(filePath))
            {
                file.WriteLine(text);
                file.Close();
            }
        }

        public static string Serialize(object instance)
        {
            if (instance == null) throw new ArgumentNullException("instance");
            string serializedString = null;
            serializedString = JSON.Instance.ToJSON(instance);
            return serializedString;
        }

        public static string Serialize(object instance, string filePath)
        {
            if (instance == null) throw new ArgumentNullException("instance");
            if (filePath == null) throw new ArgumentNullException("filePath");
            string serializedString = Serialize(instance);
            WriteText(filePath, serializedString);
            return serializedString;
        }

        public static T Deserialize<T>(string filePath)
        {
            if (filePath == null) throw new ArgumentNullException("filePath");
            string serializedString = ReadText(filePath);
            if (serializedString.HasValue())
                return JSON.Instance.ToObject<T>(serializedString);
            else
                return default(T);
        }

        public static void VerifyDirectory(string directory)
        {
            if (directory == null) throw new ArgumentNullException("directory");
            if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
        }

        public static void FileRename(string source, string destination)
        {
            if (File.Exists(source))
            {
                File.Move(source, destination);
                File.Delete(source);
            }
            else
                Log.Warning(Msg.PathNotFound(source));
        }

        public static string GetMb(long bytes)
        {
            double megas = (double) bytes/1024/1024;
            return megas.ToString("N2") + " Mb.";
        }

        public static string GetKb(long bytes)
        {
            double megas = (double) bytes/1024;
            return megas.ToString("N0") + " Kb.";
        }

        public static void SetValue(object target, string propertyName, object value)
        {
            Type pocoType = target.GetType(); // TODO: Cache to avoid multiple reflections
            PropertyInfo propertyInfo = pocoType.GetProperty(propertyName);
            if (propertyInfo != null) propertyInfo.SetValue(target, value, null);
        }

        public static object GetValue(object target, string propertyName)
        {
            Type pocoType = target.GetType(); // TODO: Cache to avoid multiple reflections
            PropertyInfo propertyInfo = pocoType.GetProperty(propertyName);
            if (propertyInfo != null)
                return propertyInfo.GetValue(target, null);
            else return null;
        }

        /// <summary>
        /// Sends the message by email
        /// </summary>
        /// <param name="subject"></param>
        /// <param name="body"></param>
        /// <param name="recipientAddress"></param>
        /// <param name="recipientName"></param>
        /// <returns></returns>
        public static void SendEmailMessage(string subject, string body, string recipientAddress, string recipientName)
        {
            var fromAddress = new MailAddress(Config.EmailAddress, Config.ApplicationName);
            var toAddress = new MailAddress(recipientAddress, recipientName);
            var smtp = new SmtpClient
                           {
                               Host = Config.SmtpAddress,
                               Port = Config.SmtpPortAddress,
                               EnableSsl = true,
                               DeliveryMethod = SmtpDeliveryMethod.Network,
                               UseDefaultCredentials = false,
                               Credentials = new NetworkCredential(fromAddress.Address, Config.SmtpPassword)
                           };
            using (var message = new MailMessage(fromAddress, toAddress)
                                     {
                                         Subject = subject,
                                         Body = body
                                     })
            {
                try
                {
                    smtp.Send(message);
                }
                catch (Exception e)
                {
                    Log.Error(
                        new ApplicationException(
                            string.Format("Error sending From {0} to {1} through {2}:{3} pass:{4}", fromAddress, toAddress, Config.SmtpAddress,
                                          Config.SmtpPortAddress, Config.SmtpPassword), e), EntryCategories.Core);
                }
            }
        }
    }
}